package com.ruicar.afs.cloud.afscase.processor.notice;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruicar.afs.cloud.afscase.approvetask.entity.WorkProcessScheduleInfo;
import com.ruicar.afs.cloud.afscase.approvetask.entity.WorkTaskPool;
import com.ruicar.afs.cloud.afscase.approvetask.service.CaseApproveRecordService;
import com.ruicar.afs.cloud.afscase.approvetask.service.WorkProcessScheduleInfoService;
import com.ruicar.afs.cloud.afscase.approvetask.service.WorkProcessScheduleInfoTempService;
import com.ruicar.afs.cloud.afscase.approvetask.service.WorkTaskPoolService;
import com.ruicar.afs.cloud.afscase.infomanagement.entity.CaseChannelInfo;
import com.ruicar.afs.cloud.afscase.infomanagement.entity.CaseContractInfo;
import com.ruicar.afs.cloud.afscase.infomanagement.entity.CaseCustInfo;
import com.ruicar.afs.cloud.afscase.infomanagement.service.CaseChannelInfoService;
import com.ruicar.afs.cloud.afscase.infomanagement.service.CaseContractInfoService;
import com.ruicar.afs.cloud.afscase.infomanagement.service.CaseCustInfoService;
import com.ruicar.afs.cloud.afscase.mq.approvesendinfo.service.ApproveLoanInfoService;
import com.ruicar.afs.cloud.afscase.processor.entity.WorkExceptionInfo;
import com.ruicar.afs.cloud.afscase.processor.enums.WorkflowType;
import com.ruicar.afs.cloud.afscase.processor.service.WorkExceptionInfoService;
import com.ruicar.afs.cloud.afscase.processor.util.WorkflowTypeUtil;
import com.ruicar.afs.cloud.common.core.enums.AfsEnumUtil;
import com.ruicar.afs.cloud.common.core.feign.api.RemoteUserService;
import com.ruicar.afs.cloud.common.core.util.SpringContextHolder;
import com.ruicar.afs.cloud.common.modules.afscorebusiness.enums.*;
import com.ruicar.afs.cloud.seats.entity.UserCollocation;
import com.ruicar.afs.cloud.seats.service.UserCollocationService;
import com.ruicar.afs.cloud.workflow.api.dto.afsprocess.request.FlowExceptionRequest;
import com.ruicar.afs.cloud.workflow.api.dto.afsprocess.request.TaskAssignRequest;
import com.ruicar.afs.cloud.workflow.api.dto.afsprocess.request.TaskCreateRequest;
import com.ruicar.afs.cloud.workflow.api.dto.afsprocess.request.UpdateBizDataRequest;
import com.ruicar.afs.cloud.workflow.api.dto.afsprocess.response.FlowExceptionResponse;
import com.ruicar.afs.cloud.workflow.api.dto.afsprocess.response.TaskAssignResponse;
import com.ruicar.afs.cloud.workflow.api.dto.afsprocess.response.TaskCreateResponse;
import com.ruicar.afs.cloud.workflow.api.dto.afsprocess.response.UpdateBizDataResponse;
import com.ruicar.afs.cloud.workflow.gwt.processor.AfsWorkFlowNoticeProcessor;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @Description 放款流程通知类接口
 * @Author yk.Li
 * @Date 2020/08/14
 */
@Component
@AllArgsConstructor
@Slf4j
public class LoanNoticeProcessor implements AfsWorkFlowNoticeProcessor {

    WorkTaskPoolService workTaskPoolService;
    WorkProcessScheduleInfoService workProcessScheduleInfoService;
    WorkProcessScheduleInfoTempService workProcessScheduleInfoTempService;
    CaseChannelInfoService caseChannelInfoService;
    CaseCustInfoService caseCustInfoService;
    UserCollocationService userCollocationService;
    RemoteUserService remoteUserService;
    CaseContractInfoService contractInfoService;
    WorkExceptionInfoService workExceptionInfoService;
    CaseApproveRecordService caseApproveRecordService;
    ApproveLoanInfoService approveLoanInfoService;

    @Override
    public List<String> afsFLowKeys() {
        return Arrays.asList(new String[]{
                WorkflowType.LOAN_APPROVAL_NEW.getAfsFlowKey(),
                WorkflowType.LOAN_APPROVAL_OLD.getAfsFlowKey(),
                WorkflowType.LOAN_GPS_AUDIT.getAfsFlowKey()
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public TaskCreateResponse taskCreated(TaskCreateRequest taskCreateRequest) {
        return SpringContextHolder.getBean(NormalNoticeProcessor.class).taskCreated(taskCreateRequest);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public TaskAssignResponse taskAssigned(TaskAssignRequest taskAssignRequest) {
        //return SpringContextHolder.getBean(NormalNoticeProcessor.class).taskAssigned(taskAssignRequest);
        //change by fangchenliang
        NormalNoticeProcessor normalNoticeProcessor=SpringContextHolder.getBean(NormalNoticeProcessor.class);
        log.info("放款分单：任务理人实例获取，创建待办任务:taskAssigned ==>{}", taskAssignRequest);
        WorkProcessScheduleInfo workflowInstance = workProcessScheduleInfoService.getById(taskAssignRequest.getBizDataId());
        CaseChannelInfo channelInfo = caseChannelInfoService.getOne(
                Wrappers.<CaseChannelInfo>lambdaQuery().eq(CaseChannelInfo::getApplyNo, workflowInstance.getApplyNo())
        );
        CaseCustInfo custInfo = caseCustInfoService.getOne(
                Wrappers.<CaseCustInfo>lambdaQuery().eq(CaseCustInfo::getApplyNo, workflowInstance.getApplyNo())
                        .eq(CaseCustInfo::getCustRole, CustRoleEnum.MIANCUST.getCode())
        );
        UserCollocation userCollocation = userCollocationService.getOne(
                Wrappers.<UserCollocation>lambdaQuery().eq(UserCollocation::getLoginName, taskAssignRequest.getUserName())
        );
        WorkTaskPool taskPool = new WorkTaskPool();
        taskPool.setStageId(Convert.toStr(workflowInstance.getId()));
        taskPool.setStageNo(workflowInstance.getStageNo());
        taskPool.setTaskNodeId(taskAssignRequest.getTaskNodeId());
        taskPool.setTaskNodeName(taskAssignRequest.getTaskName());
        taskPool.setApplyNo(workflowInstance.getApplyNo());
        taskPool.setDealerName(Objects.nonNull(channelInfo) ? channelInfo.getDealerName() : "");
        taskPool.setCustName(custInfo.getCustName());
        taskPool.setApproveStaff(taskAssignRequest.getUserName());
        // 可能处理人为经销商
        if (Objects.nonNull(channelInfo) && StrUtil.equals(taskAssignRequest.getUserName(), Convert.toStr(channelInfo.getId()))) {
            CaseContractInfo contractInfo=contractInfoService.getOne(Wrappers.<CaseContractInfo>lambdaQuery().eq(CaseContractInfo::getContractNo,workflowInstance.getContractNo()),false);
            taskPool.setApproveStaffName(contractInfo.getUserRealName());
        } else {
            taskPool.setApproveStaffName(normalNoticeProcessor.getTaskHandlerUserName(taskAssignRequest));
        }
        taskPool.setStartTime(new Date());
        taskPool.setIsOpen(WhetherEnum.NO.getCode());
        taskPool.setStartTime(new Date());
        taskPool.setProcessType(WorkflowTypeUtil.getApproveTypeCode(workflowInstance.getAfsFlowKey()));
        taskPool.setWorkflowDisposeId(taskAssignRequest.getId());
        if (Objects.nonNull(userCollocation)) {
            taskPool.setApproveLeader(userCollocation.getGroupLeaderLoginName());
            taskPool.setApproveLeaderName(userCollocation.getGroupLeader());
        }
        //add by yk.Li 2020/7/20
        taskPool.setContractNo(workflowInstance.getContractNo());
        // 是否首尾节点
        taskPool.setFirstNode(workflowInstance.getFirstTrail());
        taskPool.setLastNode(workflowInstance.getLastTrail());
        workTaskPoolService.save(taskPool);
        caseApproveRecordService.assignRecord(taskPool);
        createFirstFlowNodeForContract(workflowInstance);

        TaskAssignResponse response = new TaskAssignResponse();
        response.setSuccess(true);
        return response;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UpdateBizDataResponse updateBizData(UpdateBizDataRequest updateBizDataRequest) {
        return SpringContextHolder.getBean(NormalNoticeProcessor.class).updateBizData(updateBizDataRequest);
    }

    @Override
    public FlowExceptionResponse assignError(FlowExceptionRequest flowExceptionRequest) {
        LOGGER.info("接收到[任务分配]流程异常通知:{}", JSON.toJSONString(flowExceptionRequest));
        processFlowException(flowExceptionRequest, FlowParseEnum.ASSIGN);
        FlowExceptionResponse response = new FlowExceptionResponse();
        response.setSuccess(true);
        return response;
    }

    @Override
    public FlowExceptionResponse dataGetError(FlowExceptionRequest flowExceptionRequest) {
        LOGGER.info("接收到[数据获取]流程异常通知:{}", JSON.toJSONString(flowExceptionRequest));
        processFlowException(flowExceptionRequest, FlowParseEnum.DATA);
        FlowExceptionResponse response = new FlowExceptionResponse();
        response.setSuccess(true);
        return response;
    }

    @Override
    public FlowExceptionResponse defaultError(FlowExceptionRequest flowExceptionRequest) {
        LOGGER.info("接收到[默认(未定义)]流程异常通知:{}", JSON.toJSONString(flowExceptionRequest));
        processFlowException(flowExceptionRequest, FlowParseEnum.DEFAULT);
        FlowExceptionResponse response = new FlowExceptionResponse();
        response.setSuccess(true);
        return response;
    }

    /**
     * @Description 保存工作流返回异常信息
     * @Author yk.Li
     * @Date 2020/08/14
     */
    @Transactional
    public void processFlowException(FlowExceptionRequest flowExceptionRequest, FlowParseEnum flowParseEnum) {
        WorkProcessScheduleInfo info = workProcessScheduleInfoService.getById(flowExceptionRequest.getBizDataId());
        String flowTypeName = WorkflowTypeUtil.getApproveTypeCode(info.getAfsFlowKey());
        // 常规审批流程处理
        if (Objects.nonNull(info) && StringUtils.isNotBlank(info.getContractNo())) {
            CaseContractInfo contractInfo = contractInfoService.getOne(Wrappers.<CaseContractInfo>lambdaQuery()
                    .eq(CaseContractInfo::getContractNo, info.getContractNo()));
            WorkExceptionInfo workExceptionInfo = new WorkExceptionInfo();
            workExceptionInfo.setBusinessId(contractInfo.getId());
            workExceptionInfo.setFlowParseId(info.getId());
            workExceptionInfo.setFlowParseExceptionId(flowExceptionRequest.getExceptionId());
            workExceptionInfo.setFlowResultFlag(WhetherEnum.NO.getCode());
            workExceptionInfo.setFlowParseType(AfsEnumUtil.key(flowParseEnum));
            workExceptionInfoService.save(workExceptionInfo);

            if (StrUtil.equals(flowTypeName, LoanProcessTypeEnum.GENERAL_LOAN.getCode())) {
                contractInfo.setBusinessStage(BusinessStageEnum.WAIT_ASSIGN.getCode());
                contractInfo.setApplyStatus(ApplyStatusEnum.WAIT_ASSIGN.getState());
                contractInfo.setWorkExceptionId(workExceptionInfo.getId());
                contractInfoService.updateById(contractInfo);
            }
            log.info("流程异常接收完毕 =>合同号：{}, 异常返回ID：{}", info.getContractNo(), flowExceptionRequest.getExceptionId());
        }
    }

    private void createFirstFlowNodeForContract(WorkProcessScheduleInfo workflowInstance){
        String flowTypeName = WorkflowTypeUtil.getApproveTypeCode(workflowInstance.getAfsFlowKey());
        if (Objects.nonNull(workflowInstance)
                && StrUtil.equals(flowTypeName, LoanProcessTypeEnum.GENERAL_LOAN.getCode())) {
            List<String> applyStatusList = new ArrayList<>();
            applyStatusList.add(ApplyStatusEnum.WAIT_ASSIGN.getState());
            applyStatusList.add(ApplyStatusEnum.ASSIGNING.getState());
            if (StrUtil.equals(workflowInstance.getFirstTrail(),WhetherEnum.YES.getCode())) {
                contractInfoService.update(
                        Wrappers.<CaseContractInfo>lambdaUpdate()
                                .eq(CaseContractInfo::getContractNo, workflowInstance.getContractNo())
                                .in(CaseContractInfo::getApplyStatus, applyStatusList)
                                .set(CaseContractInfo::getApplyStatus, ApplyStatusEnum.LOAN_WAIT_APPROVE.getState())
                                .set(CaseContractInfo::getFlowNode, FlowNodeEnum.PRIMARY.getCode())
                                .set(CaseContractInfo::getBusinessStage,BusinessStageEnum.LOAN_APPROVAL.getCode())

                );
                try {
                    //通知进件系统
                    approveLoanInfoService.sendToApplyNotic(workflowInstance.getContractNo()
                            , ApplyStatusEnum.LOAN_WAIT_APPROVE);
                } catch (Exception e) {
                    log.info("通知进件系统，{}合同状态改为放款待审核失败！",workflowInstance.getContractNo(),e);
                }
            }
        }
    }
}
